package gbench.sandbox.neo4j.draft;

import static gbench.common.tree.LittleTree.MFT;
import static gbench.common.tree.LittleTree.IRecord.*;
import static gbench.common.tree.LittleTree.SimpleRecord.REC2;
import java.time.LocalDateTime;
import java.util.stream.Collectors;
import gbench.commonApp.jdbc.Neo4jApp;
import org.junit.jupiter.api.Test;

/**
 * 
 * @author gbench
 *
 */
public class MyNeo4jAppData {
    
    /**
     * Neo4jAppData 的内部数据结构演示 :
     * 双订顶点边集合: g.getEdges() 与 g.getAttributeSets() 图属性数据: g.getAttributeSets() 以 name/String->attributes/IRecord的形式结构进行保存。
     * name 可以是labelName,也可以是边name,都是全图唯一的。需要通过g的 vertex_name_renderer 或是edge_name_renderer 来给与生成。
     */
    @Test
    public void bar() {
        final var neo4jApp = Neo4jApp.newInstance(); // 创建图的应用App
        
        // 基本数据关系
        final var purchaseProto = REC( "0#vlblk","User", "1#vlblk","Product", "elblk","Purchase", // 基本关系结构 
            "createtime",LocalDateTime.now(),"shop","华联超市");// 购买关系 
        final var teachProto = REC( "0#vlblk","User", "1#vlblk","User", "elblk","Teach");// 教学关系
        final var profileProto = REC("0#vlblk","User");// 个人基本信息
        final var productProto = REC("0#vlblk","Product");// 产品信息
        
        neo4jApp.set_intialize_handler(g->{// 把交易代码也写入到边明路径中。
            final var p = g.getEdge_name_renderer();// 记录老的边名记录器
            g.setEdge_name_renderer(edge->p.apply(edge)+"$"+edge.attr("transcode",""));// 在边实体记录中增加transcode 
        },false);// 注释intialize_handler 采用增量覆盖的方式 即replace 参数使用false
        
        // 构建数据关系图 ，注意此处使用了REC2 以保证可以使用重名的键
        final var g = neo4jApp.graph( REC2( 
            
            // 双节点边,注意张三买了两次苹果,但是每次的交易码 transcode 不一样。通过交易码进行边的区分。 
            "张三/苹果", purchaseProto.derive("quality",3,"unit","斤","0#friend","王五","transcode",1),// 张三买了5斤苹果 ，张三有个朋友属性：王五
            "张三/苹果", purchaseProto.derive("quality",5,"unit","斤","0#friend","王五","transcode",2),// 张三买了5斤苹果 ，张三有个朋友属性：王五
            "张三/葡萄", purchaseProto.derive("quality",3,"unit","斤","transcode",1),// 张三买了3斤葡萄 
            "张三/张三", teachProto.derive("subject","数学"), // 张三自学数学     "李四/张三", teachProto.derive("subject","语文"), // 李四教张三语文     // 单节点边。 
            
             // 单顶点属性 :注意单节点边的属性，名称需要符合定性属性名的命名规范。例如:'$name','0#name' 或是 '苹果.price' 这样的式样。 这里的单引号'用于分隔，实际使用 不要输入。
            "张三", profileProto.derive("$sex","女","$birth","1980-8-12"), // 张三的属性数据
            "苹果", productProto.derive("$price",5.8,"$title","红富士苹果","$sku","F0001"),// 苹果的属性数据
            "葡萄", productProto.derive("$price",9.8,"$title","龙眼葡萄","$sku","F0002"), // 葡萄的属性数据。
            
            //其他节点
            "a/b/c/d",REC("pathcode",1,"transcode",1,"$category","小写字母"),
            "a/b/c/d",REC("pathcode",2,"transcode",2),
            "早/中/晚",REC("pathcode",2,"transcode",1)
        )); // graph 
        
        // 打印关系图
        System.out.println(g);
        System.out.println("\n打印边信息");
        
        // 双订顶点边集合: g.getEdges() 与 g.getAttributeSets() 图属性数据: g.getAttributeSets() 以 name/String->attributes/IRecord的形式结构进行保存。
        // name 可以是labelName,也可以是边name,都是全图唯一的。需要通过g的 vertex_name_renderer 或是edge_name_renderer 来给与生成。
        final var edgeData = g.getEdges_workingcache().stream().collect(Collectors.groupingBy(g.getEdge_name_renderer()));// 双顶点边EdgeInfo信息集合。中包含 边节点数据
        REC(g.getAttributeSets())
        .filter(kvp->kvp.key().startsWith("e") && kvp.val2rec().get("pathcode")!=null) // attribute 中只包含边数据。提取边属性，边属性 默认以e开头。
        .foreach((key,v)->{
            System.out.println(MFT("{0} ---> {1}, edges:{2}",key,v,edgeData.get(key)));
        });// foreach
        
    }//bar

}
